#pragma once

#include<iostream>
#include<string>
#include<typeinfo>
#include<cassert>
#include<unistd.h>
#include<any>


class Any
{
public:
    Any()
    :_holder(nullptr)
    {}

    template<class T>
    Any(const T& val)
    :_holder(new placeholder<T>(val))
    {}

    Any(const Any & val)
    :_holder(val._holder->clone())
    {}

    ~Any()
    {
        if(nullptr != _holder)
            delete _holder;
    }

    template<class T>
    Any & operator=(const T &val)
    {
        Any(val).swap(*this);
        return *this;
    }
    Any & operator=(const Any& val)
    {
        Any(val).swap(*this);
        return *this;
    }

    template<class T>
    T * get()
    {
        assert(nullptr != _holder);
        assert(_holder->type() == typeid(T));
        return &(((placeholder<T>*)_holder)->_val);
    }

    void swap(Any &val)
    {
        std::swap(this->_holder,val._holder);
    }

private:
    class holder
    {
    public:
        virtual ~holder(){};
        holder() = default;

        virtual const std::type_info & type() = 0;
        virtual holder* clone() = 0;
    };

    template<class T> 
    class placeholder : public holder
    {  
    public:
        placeholder() = default;
        placeholder(const T& val)
        :_val(val)
        {}
        
        virtual const std::type_info & type()
        {
            return typeid(T);
        }
        virtual holder* clone()
        {
            return new placeholder(this->_val);
        }
        ~placeholder() = default;
    public:
        T _val;
    };

private:
    holder * _holder;
};


void test_any1()
{
    Any a(1);

    std::cout<<*a.get<int>()<<std::endl;

    a = double(5.5);
    std::cout<<*a.get<double>()<<std::endl;

}

class Test{
    public:
        Test() {std::cout << "构造" << std::endl;}
        Test(const Test &t) {std::cout << "拷贝" << std::endl;}
        ~Test() {std::cout << "析构" << std::endl;}
};

void test_any2()
{
    Any a;
    {
        Test t;
        a = t;
    }

   // while(1) sleep(1);
}



//c++标准库 any
void test_any3()
{
    std::any a;
    a = 10;
    int *pi = std::any_cast<int>(&a);
    std::cout << *pi << std::endl;

    a = std::string("hello");
    std::string *ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl;
}